<?php

namespace common\db;

use Yii;
use yii\web\NotFoundHttpException;
use yii\behaviors\TimestampBehavior;
use yii\db\Expression;
use common\base\ModelHttpException;

/**
 * ActiveRecord is the base class for classes representing relational data in terms of objects.
 *
 * @author emhome<emhome@163.com>
 * @since 2.0
 */
class ActiveRecord extends \yii\db\ActiveRecord {

    use \common\traits\ModelErrors;
    use \common\traits\SearchForBuildQuery;

    /**
     * @inheritdoc
     */
    public function behaviors() {
        $timestampBehavior = [
            'class' => TimestampBehavior::className(),
        ];
        if (!$this->hasAttribute('created_at')) {
            $timestampBehavior['createdAtAttribute'] = false;
        }
        if (!$this->hasAttribute('updated_at')) {
            $timestampBehavior['updatedAtAttribute'] = false;
        }
        return [
            $timestampBehavior
        ];
    }

    /**
     * {@inheritdoc}
     * @return ActiveQuery the newly created [[ActiveQuery]] instance.
     */
    public static function find() {
        return Yii::createObject(ActiveQuery::className(), [get_called_class()]);
    }

    /**
     * {@inheritdoc}
     * @return ActiveQuery the newly created [[ActiveQuery]] instance.
     */
    public static function callProcedure($name, $params = []) {
        $db = static::getDb();
        $sql = "CALL $name";
        $tempKeys = [];
        $inParams = [];
        $outFileds = [];
        if (!empty($params)) {
            foreach ($params as $key => $vls) {
                if (is_int($key)) {
                    $outkey = '@' . ltrim($vls, '@');
                    $tempKeys[] = $outkey;
                    $outFileds[] = $outkey;
                } elseif (strpos($key, '@') === 0) {
                    $tempKeys[] = $key;
                    $outFileds[] = $key;
                } elseif (strpos($key, ':') === 0) {
                    $tempKeys[] = $key;
                    $inParams[$key] = $vls;
                } else {
                    $tempKeys[] = ':' . $key;
                    $inParams[':' . $key] = $vls;
                }
            }
        }
        if (!empty($tempKeys)) {
            $sql .= '(' . implode(',', $tempKeys) . ')';
        }
        $sql .= ';';
        $query = $db->createCommand($sql)->bindValues($inParams);
        if (empty($outFileds)) {
            return $query;
        }
        $query->execute();
        return $db->createCommand('SELECT ' . implode(',', $outFileds) . ';');
    }

    /**
     * 加入记录软删除
     * @param boolean $hard 是否真实删除
     * {@inheritdoc}
     */
    public function delete($hard = false) {
        if ($hard == false && $this->hasAttribute('deleted_at')) {
            $this->deleted_at = time();
            return $this->save();
        }
        return parent::delete();
    }

    /**
     * 查询对象是否存在存在返回记录不存在创建
     * @params $condition
     * @return static
     */
    public static function findOrNew($condition) {
        $model = static::findOne($condition);
        if ($model === null) {
            $className = self::className();
            $model = new $className();
            if (is_array($condition)) {
                $model->setAttributes($condition);
            }
        }
        return $model;
    }

    /**
     * 查询对象是否存在存在返回记录不存在创建
     * @params $condition
     * @return static
     */
    public static function findOrCreate($condition) {
        $model = static::findOne($condition);
        if ($model === null) {
            $className = self::className();
            $model = new $className();
            if (is_array($condition)) {
                $model->setAttributes($condition);
            }
            if (!$model->save()) {
                throw new ModelHttpException('数据更新异常', $model->getErrorMsg());
            }
        }
        return $model;
    }

    /**
     * 查询对象是否存在存在返回记录不存在返回异常
     * @params $condition
     * @return static
     */
    public static function findOrFail($condition) {
        $model = static::findOne($condition);
        if ($model === null) {
            throw new NotFoundHttpException('未找到数据模型对应的记录！');
        }
        return $model;
    }

    /**
     * {@inheritdoc}
     * @return ActiveQuery the newly created [[ActiveQuery]] instance.
     */
    public static function findActive($alias = null, $state = false) {
        $query = static::find();
        if ($alias) {
            $query->alias($alias);
        }
        $query->active($state);
        return $query;
    }

    public function hasOneX($class, $link, $pk) {
        /* @var $class SequenceActiveRecord */
        /* @var $query ActiveQuery */
        $query = $class::findx($pk);
        $query->primaryModel = $this;
        $query->link = $link;
        $query->multiple = false;
        return $query;
    }

    public function hasManyX($class, $link, $pk) {
        /* @var $class SequenceActiveRecord */
        /* @var $query ActiveQuery */
        $query = $class::findx($pk);
        $query->primaryModel = $this;
        $query->link = $link;
        $query->multiple = true;
        return $query;
    }

    /**
     * Sets the named attribute value.
     * @param string $name the attribute name
     * @param mixed $value the attribute value.
     * @throws InvalidArgumentException if the named attribute does not exist.
     * @see hasAttribute()
     */
    public function setGeometryAttribute($name, $value) {
        if (is_array($value) && count($value) == 2) {
            list($lng, $lat) = $value;
            //$value = new Expression("GEOMFROMTEXT('POINT($lng $lat)')");
            $value = new Expression("POINT($lng,$lat)");
        }
        $this->setAttribute($name, $value);
    }

    /**
     * {@inheritdoc}
     * @return ActiveQuery the newly created [[ActiveQuery]] instance.
     */
    public function afterSave($insert, $changedAttributes) {
        parent::afterSave($insert, $changedAttributes);
        Yii::error([
            $this->tableName(),
            $this->className(),
            $insert,
            $changedAttributes,
        ], __METHOD__);
    }

}
